import os

os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
import cv2
import requests
import numpy as np
import threading
import time
import json
from datetime import datetime
import logging
from queue import Queue

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class CameraStreamClient:
    def __init__(self, api_base_url="http://39.104.78.210:8050", camera_index=0):
        self.api_base_url = api_base_url
        self.camera_index = camera_index
        self.cap = None
        self.is_streaming = False
        self.frame_interval = 0.02  # 50 FPS (1/50 = 0.02)
        self.frame_queue = Queue(maxsize=10)  # 帧队列
        self.request_count = 0
        self.last_log_time = time.time()

    def start_stream(self):
        """启动摄像头并开始发送视频流"""
        try:
            # 初始化摄像头 - 使用DirectShow（Windows）
            self.cap = cv2.VideoCapture(self.camera_index, cv2.CAP_DSHOW)
            if not self.cap.isOpened():
                logger.error("无法打开摄像头")
                return False

            # 优化摄像头参数
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)  # 降低分辨率
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
            self.cap.set(cv2.CAP_PROP_FPS, 60)  # 提高摄像头FPS
            self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)  # 减少缓冲区大小
            self.cap.set(cv2.CAP_PROP_AUTOFOCUS, 0)  # 关闭自动对焦

            self.is_streaming = True
            logger.info("摄像头流开始")

            # 启动帧捕获线程
            capture_thread = threading.Thread(target=self._capture_frames)
            capture_thread.daemon = True
            capture_thread.start()

            # 启动多个发送线程
            for i in range(3):  # 启动3个发送线程提高并发
                send_thread = threading.Thread(target=self._send_frames, name=f"SendThread-{i}")
                send_thread.daemon = True
                send_thread.start()

            # 启动显示线程
            display_thread = threading.Thread(target=self._display_frames)
            display_thread.daemon = True
            display_thread.start()

            # 启动性能监控线程
            monitor_thread = threading.Thread(target=self._monitor_performance)
            monitor_thread.daemon = True
            monitor_thread.start()

            return True

        except Exception as e:
            logger.error(f"启动摄像头流失败: {str(e)}")
            return False

    def _capture_frames(self):
        """专门捕获帧的线程"""
        while self.is_streaming and self.cap.isOpened():
            try:
                ret, frame = self.cap.read()
                if not ret:
                    logger.warning("无法读取摄像头帧")
                    time.sleep(0.01)
                    continue

                # 立即调整大小
                frame = cv2.resize(frame, (320, 240))

                # 如果队列未满，添加帧
                if not self.frame_queue.full():
                    self.frame_queue.put(frame)
                else:
                    # 队列满时丢弃最旧的帧
                    try:
                        self.frame_queue.get_nowait()
                        self.frame_queue.put(frame)
                    except:
                        pass

            except Exception as e:
                logger.error(f"捕获帧时发生错误: {str(e)}")
                time.sleep(0.01)

    def _send_frames(self):
        """发送帧到API服务 - 多线程版本"""
        thread_name = threading.current_thread().name
        last_send_time = 0

        while self.is_streaming:
            try:
                current_time = time.time()

                # 控制发送频率
                if current_time - last_send_time < self.frame_interval:
                    time.sleep(0.001)
                    continue

                # 从队列获取帧
                try:
                    frame = self.frame_queue.get_nowait()
                except:
                    time.sleep(0.001)
                    continue

                # 编码为JPEG - 降低质量提高速度
                _, img_encoded = cv2.imencode('.jpg', frame, [
                    cv2.IMWRITE_JPEG_QUALITY, 60,  # 降低质量
                    cv2.IMWRITE_JPEG_OPTIMIZE, 1
                ])

                # 准备发送数据
                files = {'image': ('frame.jpg', img_encoded.tobytes(), 'image/jpeg')}

                # 发送到人脸识别API - 使用更短的超时
                response = requests.post(
                    f"{self.api_base_url}/search_face",
                    files=files,
                    timeout=2  # 缩短超时时间
                )

                if response.status_code == 200:
                    result = response.json()
                    if result.get('query_face_detected', False):
                        faces = result.get('search_results', [])
                        logger.info(f"检测到 {len(faces)} 个人脸: {faces}")

                self.request_count += 1
                last_send_time = current_time

            except requests.exceptions.Timeout:
                # 超时是预期的，继续处理下一帧
                pass
            except requests.exceptions.RequestException as e:
                logger.warning(f"{thread_name} - API请求失败: {str(e)}")
                time.sleep(0.1)
            except Exception as e:
                logger.error(f"{thread_name} - 发送帧时发生错误: {str(e)}")
                time.sleep(0.1)

    def _monitor_performance(self):
        """监控性能"""
        while self.is_streaming:
            time.sleep(2)
            current_time = time.time()
            elapsed = current_time - self.last_log_time
            if elapsed > 0:
                fps = self.request_count / elapsed
                logger.info(f"当前请求频率: {fps:.1f} FPS, 队列大小: {self.frame_queue.qsize()}")
                self.request_count = 0
                self.last_log_time = current_time

    def _display_frames(self):
        """本地显示摄像头帧"""
        while self.is_streaming:
            try:
                # 从队列获取最新帧显示
                if not self.frame_queue.empty():
                    frame = self.frame_queue.queue[-1]  # 获取最新帧

                    # 在帧上添加时间戳
                    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    cv2.putText(frame, timestamp, (10, 20),
                                cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)

                    cv2.imshow('Camera Stream', frame)

                    # 按 'q' 退出
                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        self.stop_stream()
                        break

            except Exception as e:
                logger.error(f"显示帧时发生错误: {str(e)}")
                time.sleep(0.1)

        cv2.destroyAllWindows()

    def stop_stream(self):
        """停止摄像头流"""
        self.is_streaming = False
        if self.cap:
            self.cap.release()
        logger.info("摄像头流已停止")

    def test_connection(self):
        """测试API连接"""
        try:
            response = requests.get(f"{self.api_base_url}/", timeout=3)
            if response.status_code == 200:
                logger.info("API服务连接成功")
                return True
            else:
                logger.error(f"API服务连接失败: HTTP {response.status_code}")
                return False
        except Exception as e:
            logger.error(f"API服务连接测试失败: {str(e)}")
            return False


def main():
    # 配置参数
    API_BASE_URL = "http://39.104.78.210:8050"
    CAMERA_INDEX = 0

    # 创建客户端
    client = CameraStreamClient(api_base_url=API_BASE_URL, camera_index=CAMERA_INDEX)

    # 测试连接
    if not client.test_connection():
        logger.error("无法连接到API服务，请检查服务是否运行")
        return

    # 启动摄像头流
    if not client.start_stream():
        logger.error("无法启动摄像头流")
        return

    logger.info("摄像头流已启动，按 Ctrl+C 停止")

    try:
        # 保持主线程运行
        while client.is_streaming:
            time.sleep(1)

    except KeyboardInterrupt:
        logger.info("接收到中断信号，停止流")
    finally:
        client.stop_stream()


if __name__ == "__main__":
    main()